package com.zg.datapush.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 推送日志记录器
 * 用于在推送过程中记录详细的步骤日志
 * @author zg
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class PushLogRecorder {

    private final DpPushLogService pushLogService;

    // 使用ThreadLocal存储当前线程的推送记录ID和步骤计数器
    private final ThreadLocal<Long> currentRecordId = new ThreadLocal<>();
    private final ThreadLocal<AtomicInteger> stepCounter = new ThreadLocal<>();

    /**
     * 开始记录推送日志
     */
    public void startRecording(Long recordId) {
        currentRecordId.set(recordId);
        stepCounter.set(new AtomicInteger(1));
    }

    /**
     * 记录步骤开始
     */
    public Long logStepStart(String stepName, String className, String methodName) {
        Long recordId = currentRecordId.get();
        if (recordId == null) {
            log.warn("推送记录ID未设置，无法记录日志");
            return null;
        }

        AtomicInteger counter = stepCounter.get();
        if (counter == null) {
            counter = new AtomicInteger(1);
            stepCounter.set(counter);
        }

        int stepOrder = counter.getAndIncrement();
        return pushLogService.createLog(recordId, stepName, stepOrder, className, methodName).getId();
    }

    /**
     * 记录步骤成功
     */
    public void logStepSuccess(Long logId, Object inputData, Object outputData) {
        if (logId != null) {
            pushLogService.updateLogSuccess(logId, inputData, outputData);
        }
    }

    /**
     * 记录步骤失败
     */
    public void logStepFailed(Long logId, Object inputData, Exception exception) {
        if (logId != null) {
            pushLogService.updateLogFailed(logId, inputData, exception);
        }
    }

    /**
     * 结束记录推送日志
     */
    public void endRecording() {
        currentRecordId.remove();
        stepCounter.remove();
    }

    /**
     * 执行带日志记录的方法
     */
    public <T> T executeWithLog(String stepName, String className, String methodName,
                                Object inputData, LoggedOperation<T> operation) throws Exception {
        Long logId = logStepStart(stepName, className, methodName);
        try {
            T result = operation.execute();
            logStepSuccess(logId, inputData, result);
            return result;
        } catch (Exception e) {
            logStepFailed(logId, inputData, e);
            throw e;
        }
    }

    /**
     * 执行带日志记录的无返回值方法
     */
    public void executeWithLog(String stepName, String className, String methodName,
                               Object inputData, LoggedVoidOperation operation) throws Exception {
        Long logId = logStepStart(stepName, className, methodName);
        try {
            operation.execute();
            logStepSuccess(logId, inputData, "执行成功");
        } catch (Exception e) {
            logStepFailed(logId, inputData, e);
            throw e;
        }
    }

    /**
     * 带返回值的操作接口
     */
    @FunctionalInterface
    public interface LoggedOperation<T> {
        T execute() throws Exception;
    }

    /**
     * 无返回值的操作接口
     */
    @FunctionalInterface
    public interface LoggedVoidOperation {
        void execute() throws Exception;
    }
}
